-------------------------------------------------------------------------------
-- Завершение слова в редакторе. © SimSU
-------------------------------------------------------------------------------

---- Настройки
local function Settings()
-- Начало файла Profile\SimSU\Editor_WordComplete.cfg
return{
  Key="CtrlSpace"; Prior=51; -- Принять завершение.
  KeyList="CtrlSpace"; --PriorList=50; -- Список автозавершения.

  Auto=true; -- Автозавершение разрешено.
  ThatWord="[%w_]+"; -- Что считается словом.
  MaxLines=500; -- Число строк для поиска продолжения.
  MaxTime=5; -- Время показа и жизни автоматического завершения.
  Color=15; -- Цвет завершения.
}
-- Конец файла Profile\SimSU\Editor_WordComplete.cfg
end

---- Локализация
_G.far.lang=far.lang or win.GetEnv("farlang")
-- Встроенные языки / Buildin laguages
local function Messages()
if far.lang=="Russian" then
-- Начало файла Profile\SimSU\Editor_WordCompleteRussian.lng
return{
  Descr="Принять завершение слова. © SimSU";
  DescrList="Список завершенных слов. © SimSU";
}
-- Конец файла Profile\SimSU\Editor_WordCompleteRussian.lng
else--if far.lang=="English" then
-- Begin of file Profile\SimSU\Editor_WordCompleteEnglish.lng
return{
  Descr="Принять завершение слова. © SimSU";
  DescrList="Список завершенных слов. © SimSU";
}
-- End of file Profile\SimSU\Editor_WordCompleteEnglish.lng
end end

local M=(loadfile(win.GetEnv("FARPROFILE").."\\SimSU\\Editor_WordComplete"..far.lang..".lng") or Messages)()
local S=(loadfile(win.GetEnv("FARLOCALPROFILE").."\\SimSU\\Editor_WordComplete.cfg") or loadfile(win.GetEnv("FARPROFILE").."\\SimSU\\Editor_WordComplete.cfg") or Settings)()

local SimSU=SimSU or {}
SimSU.Editor_WordComplete={}
-------------------------------------------------------------------------------
local ThatWord=S.ThatWord or "[%w_]+"
local _ThatWord="^("..ThatWord..")"
local ThatWord_="("..ThatWord..")$"
local MaxLines=S.MaxLines or 500
local MaxTime=S.MaxTime or 5
local Color=S.Color or 15
local Exclude=S.Exclude or ""

local Complete
local t=1

function SimSU.Editor_WordComplete.EnableAuto(Switch)
  local Prev= S.Auto or false
  S.Auto= Switch==1 and true or Switch==-1 and false or not S.Auto
  return Prev
end

function SimSU.Editor_WordComplete.GetWord(Line,Pos)
  local Line= Line or Editor.CurLine; local Pos= Pos or Editor.RealPos
  local s=editor.GetString(nil,Line,3)
  local b,e = s:cfind(_ThatWord,Pos); Pos= e or Pos-1
  local b,e,w=s:sub(1,Pos):cfind(ThatWord_); return w,b,e
end

function SimSU.Editor_WordComplete.FindNearest(Word,Line)
  Line= Line or Editor.CurLine
  if not Word then Word = SimSU.Editor_WordComplete.GetWord(Line,Editor.CurPos) end
  if not Word then return end
  local W=Word:upper(); L=W:len()
  local s=editor.GetString(nil,Line,3)
  local Lines=Editor.Lines
  local Beg,End
  for i=1,MaxLines do
    for w in s:gmatch(ThatWord) do if w:upper():find(W,1,true)==1 and w:len()>L then return w end end
    if Line-i>1 then s=editor.GetString(nil,Line-i,3) else s="" end
    for w in s:gmatch(ThatWord) do if w:upper():find(W,1,true)==1 and w:len()>L then return w end end
    if Line+i<Lines then s=editor.GetString(nil,Line+i,3) else s="" end
  end
end

function SimSU.Editor_WordComplete.Update()
  if Complete then
    local TitleBar=Far.Cfg_Get("Editor","ShowTitleBar")=="true" and 1 or 0
    local Inf=editor.GetInfo()
    far.Text(Inf.CurTabPos-Inf.LeftPos,Inf.CurLine-Inf.TopScreenLine+TitleBar,Color,Complete)
  else
    editor.Redraw()
  end
end

function SimSU.Editor_WordComplete.Complete(Rec)
  if Rec.EventType==far.Flags.KEY_EVENT and Rec.VirtualKeyCode==0 and Complete then
    if t<MaxTime then t=t+1 else Complete=nil; editor.Redraw() end
  elseif Rec.KeyDown then
    local Key=far.InputRecordToName(Rec)
    if Key:len(1)==1 and Key:find(ThatWord) then
      local w,b,e = SimSU.Editor_WordComplete.GetWord()
      w= w and w..Key or Key
      if not e or e+1==Editor.RealPos then
        local W=SimSU.Editor_WordComplete.FindNearest(w)
        if W then
          Complete=W:sub(w:len()+1); t=1
        elseif Complete then
          Complete=nil
        end
      end
    elseif Complete then
      if not((Key=="Ctrl" or Key=="RCtrl" or Key=="Alt" or Key=="RAlt" or Key=="Shift") and S.Key:find(Key,1,true)) then Complete=nil; SimSU.Editor_WordComplete.Update() end
    end
  end
  if Complete then SimSU.Editor_WordComplete.Update() end
end

function SimSU.Editor_WordComplete.List()
  local First=Editor.CurLine-MaxLines>0 and First-MaxLines or 1
  local Last=Editor.CurLine+MaxLines<Editor.Lines and Editor.CurLine+MaxLines or Editor.Lines
  local Items={}; local s
  for i=First,Last do
    s=editor.GetString(nil,i,3)
    for w in s:gmatch(ThatWord) do Items[#Items+1]=w end
  end
  local w,b,e = SimSU.Editor_WordComplete.GetWord()
  Editor.Undo(0)
  if w then editor.Select(nil,1,0,b,e-b+1,1) else w="" end
  Items=Menu.Show(table.concat(Items,"\n"),nil,0x3+0x10+0x20+0x40+0x100,w)
  if Items~="" then
    editor.DeleteBlock(); print(Items)
  else
    Editor.Sel(4)
  end
  Editor.Undo(1)
end
-------------------------------------------------------------------------------
if not Macro then return {Editor_WordComplete=SimSU.Editor_WordComplete} end

local ok, mod = pcall(require,"SimSU.Editor_WordComplete"); if ok then SimSU=mod else _G.SimSU=SimSU end
-------------------------------------------------------------------------------

Event {group="EditorInput"; priority=S.Prior; description=M.Descr;
  condition=function(Rec) return S.Auto end;
  action=SimSU.Editor_WordComplete.Complete;
}
Macro {area="Editor"; key=S.Key; priority=S.Prior; description=M.Descr;
  condition=function() return Complete end;
  action=function() print(Complete) Complete=nil end;
}
Macro {area="Editor"; key=S.KeyList; priority=S.PriorList; description=M.DescrList;
  condition=function() return not Complete end;
  action=SimSU.Editor_WordComplete.List;
}
